package com.cloudbroker.bcs.csvc.uc.facade.service;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.cloudbroker.bcs.common.jres.util.JresUtil;
import com.cloudbroker.bcs.common.util.ReflectionUtil;
import com.cloudbroker.bcs.common.util.VOUtil;
import com.cloudbroker.bcs.common.util.ValueUtil;
import com.cloudbroker.bcs.csvc.uc.api.constants.UCErrorCodes;
import com.cloudbroker.bcs.csvc.uc.api.constants.UCFields;
import com.cloudbroker.bcs.csvc.uc.api.util.UCUtil;
import com.cloudbroker.bcs.csvc.uc.api.vo.request.base.UCT2Form;
import com.hundsun.t2sdk.common.core.context.ContextUtil;
import com.hundsun.t2sdk.common.share.dataset.MapWriter;
import com.hundsun.t2sdk.common.util.ResourceUtils;
import com.hundsun.t2sdk.impl.client.T2Services;
import com.hundsun.t2sdk.interfaces.IClient;
import com.hundsun.t2sdk.interfaces.T2SDKException;
import com.hundsun.t2sdk.interfaces.share.dataset.IDatasets;
import com.hundsun.t2sdk.interfaces.share.event.EventReturnCode;
import com.hundsun.t2sdk.interfaces.share.event.EventTagdef;
import com.hundsun.t2sdk.interfaces.share.event.EventType;
import com.hundsun.t2sdk.interfaces.share.event.IEvent;

@Service
public class T2RemoteService {
    
    private static final Logger LOG = LoggerFactory.getLogger(T2RemoteService.class);
    private T2Services sdkServices = null;
    
    @PostConstruct
    public void init() {
        try {
            isWindowsOS();
            
            // 获得T2Services的实例
            sdkServices = T2Services.getInstance();
            // 加载t2sdk-config.xml配置并初始化连接
            sdkServices.setT2sdkConfigString("classpath:t2sdk-config.xml");
            sdkServices.init();
            sdkServices.start();
        } catch (Exception e) {
            LOG.error(e.toString(), e);
        }
    }
    
    private boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }
    
    private IClient getIClient(String nodeName) throws T2SDKException {
        return sdkServices.getClient(nodeName);
    }
    
    public <T> T callT2(String functionId, UCT2Form param, Class<T> clazz) {
        param.setFunction_id(functionId);
        return JresUtil.bodyProtocolToBean(callT2Inner(param,clazz), clazz);
    }
    
    private<T> Map<String, Object> callT2Inner(UCT2Form param, Class<T> clazz) {
        boolean isList = true;
        try {
            clazz.getDeclaredField("result_list");
        } catch (NoSuchFieldException e) {
            isList = false;
        }
        String functionId = param.getFunction_id();
        LOG.info("callT2:functionId[" + functionId + "] [api->uc]" + param);
        IEvent event = ContextUtil.getServiceContext().getEventFactory()
                .getEventByAlias(functionId, EventType.ET_REQUEST);

        String nodeName = getParentNameInConfig(functionId);
        String tag_sub_system_no = ValueUtil.getString(param.getTag_sub_system_no());
        if (!StringUtils.isBlank(tag_sub_system_no)) {
            event.setStringAttributeValue(EventTagdef.TAG_SUB_SYSTEM_NO, tag_sub_system_no);
        }
        MapWriter mw = new MapWriter();
        
        for (Entry<String, Field> entry : ReflectionUtil.listAllFields(param.getClass()).entrySet()) {
            mw.put(entry.getKey(), ReflectionUtil.getValueRough(param, entry.getValue()));
        }
        //event.set
        event.putEventData(mw.getDataset());
        IEvent resultEvt;
        try {
            resultEvt = getIClient(nodeName).sendReceive(event);
            LOG.info("请求包发送成功" + resultEvt);
        } catch (T2SDKException e) {
            e.printStackTrace();
            LOG.error("call T2 exception", e);
            return UCUtil.genCommErrorResult();
        }
        // 获得结果集
        IDatasets dss = resultEvt.getEventDatas();
        
        Map<String, Object> result = new HashMap<String, Object>();
        if (dss != null) {
            int datasetCount = dss.getDatasetCount();
            if (1 > datasetCount) {
                // 没结果失败
                return VOUtil.genErrorResult(UCErrorCodes.COMMON_ERROR, "没有结果");
            }
            if (1 < datasetCount) {
                LOG.warn("more than one dataset, only take first");
            }
            int rc = dss.getDataset(0).getRowCount();
            if (param.getIsResultList() || isList ) {
                List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(rc);
                dss.getDataset(0).beforeFirst();
                while (dss.getDataset(0).hasNext()) {
                    dss.getDataset(0).next();
                    
                    Map<String, Object> rowResult = new HashMap<String, Object>();
                    int lc = dss.getDataset(0).getColumnCount();
                    for (int i = 1; i <= lc; i++) {
                        String v = null;
                        try {
                            v = dss.getDataset(0).getString(i);
//                            v = new String(dss.getDataset(0).getString(i).getBytes("UTF-8"));
//
                            rowResult.put(dss.getDataset(0).getColumnName(i),""+v);
                        } catch (Exception e) {
                            LOG.error(e.toString(), e);
                        }
                    }
                    resultList.add(rowResult);
                }
                result = new HashMap<String, Object>();
                result.put(UCFields.RESULT_LIST, resultList);
            } else {
                if (dss.getDataset(0).getColumnName(0) != null) {
                    result = new HashMap<String, Object>();
                    result.put(dss.getDataset(0).getColumnName(0), dss.getDataset(0).getValue(0));
                } else {
                    int columnCount = dss.getDataset(0).getColumnCount();
                    // 遍历单个结果集列信息
                    for (int j = 1; j <= columnCount; j++) {
                        try {
//                            String v = new String(((String) dss.getDataset(0).getValue(j)).getBytes("UTF-8"));
                            String v = dss.getDataset(0).getString(j);
//                             String v = new String(dss.getDataset(0).getString(j).getBytes("UTF-8"));
//                           v = new String(dss.getDataset(0).getString(i).getBytes("UTF-8"));
                            result.put(dss.getDataset(0).getColumnName(j), v);
                        } catch (Exception e) {
                            LOG.error(e.toString(), e);
                            continue;
                        }
                    }
                }
            }
            
        }
        LOG.info("callT2:functionId[" + functionId + "] [uc->api]" + result);
        int returnCode = resultEvt.getReturnCode();
        LOG.info("UC Error Code :" + returnCode);
        if (EventReturnCode.I_OK == returnCode) { // 业务正常
            if (!result.containsKey(UCFields.ERROR_NO)) {
                VOUtil.setSuccessResult(result, ValueUtil.getString(result.get(UCFields.ERROR_INFO)));
            }
            return result;
        }
        if (!result.containsKey(UCFields.ERROR_NO)) {
            String errorNo = resultEvt.getErrorNo();
            if ("0".equals(errorNo)) {
                return VOUtil.genErrorResult(ValueUtil.getString(returnCode), "");
            }
            return VOUtil.genErrorResult(ValueUtil.getString(errorNo), resultEvt.getErrorInfo());
        }
        LOG.error("call remote uc t2 server error: error_no is {} and error_info is {}  ",
                ValueUtil.getString(result.get(UCFields.ERROR_NO)),
                ValueUtil.getString(result.get(UCFields.ERROR_INFO)));
        return VOUtil.genErrorResult(ValueUtil.getString(result.get(UCFields.ERROR_NO)),
                ValueUtil.getString(result.get(UCFields.ERROR_INFO)));
        
    }

    private static String getParentNameInConfig(String functionId) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            URL url = ResourceUtils.getURL("classpath:t2sdk-config.xml");
            Document docu = builder.parse(url.openStream());
            NodeList nl = docu.getElementsByTagName("parent");
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                NamedNodeMap nodeMap = node.getAttributes();
                String nodeName = null;
                boolean getNode = false;
                for (int j = 0; j < node.getAttributes().getLength(); j++) {
                    Node attrNode = nodeMap.item(j);
                    String nodeValue = attrNode.getNodeValue();
                    if ("parentName".equals(attrNode.getNodeName())) {
                        nodeName = nodeValue;
                    } else if ("functionId".equals(attrNode.getNodeName())) {
                        nodeValue = nodeValue.replace("*", "\\w+");
                        getNode = functionId.matches(nodeValue);
                    }
                }
                if (getNode) {
                    return nodeName;
                }
            }
        } catch (ParserConfigurationException | IOException | SAXException e) {
            e.printStackTrace();
        }
        return "";
    }
    
    public static void main(String[] args) {
        System.out.println("5070001".matches("507\\w+"));
    }
}
